package main

import (
	"fmt"
	"log"
	"os"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

// 用户模型 - 存储用户基本信息
type User struct {
	ID            int64     `json:"id" gorm:"primaryKey;autoIncrement"`
	Username      string    `json:"username" gorm:"size:50;unique;not null"`
	PasswordHash  string    `json:"-" gorm:"size:255;not null"` // 不对外暴露密码哈希
	Nickname      string    `json:"nickname" gorm:"size:50;not null"`
	Avatar        string    `json:"avatar" gorm:"size:255"`
	CreatedAt     time.Time `json:"created_at"`
	LastLoginAt   time.Time `json:"last_login_at"`

	// 修仙相关属性
	Realm         string    `json:"realm" gorm:"size:50;not null;default:'练气期'"` // 修仙境界
	RealmLevel    int       `json:"realm_level" gorm:"not null;default:1"`         // 境界小层（如练气期三层）
	Cultivation   int64     `json:"cultivation" gorm:"not null;default:0"`        // 修为值

	// 基础属性
	HP            int64     `json:"hp" gorm:"not null;default:100"`               // 气血
	Attack        int64     `json:"attack" gorm:"not null;default:10"`            // 攻击
	Defense       int64     `json:"defense" gorm:"not null;default:5"`            // 防御
	Speed         int64     `json:"speed" gorm:"not null;default:5"`              // 速度

	// 特殊属性
	Lifespan      int64     `json:"lifespan" gorm:"not null;default:100"`         // 寿元
	Talent        int       `json:"talent" gorm:"not null;default:10"`            // 根骨
	Comprehension int       `json:"comprehension" gorm:"not null;default:10"`     // 悟性
	Luck          int       `json:"luck" gorm:"not null;default:10"`              // 运气

	// 资源
	SpiritStone   int64     `json:"spirit_stone" gorm:"not null;default:1000"`    // 灵石
}

// 物品模型 - 表示游戏中的各种物品
type Item struct {
	ID          int64     `json:"id" gorm:"primaryKey;autoIncrement"`
	Name        string    `json:"name" gorm:"size:100;not null"`
	Type        string    `json:"type" gorm:"size:50;not null"` // 物品类型：材料、丹药、法宝、符箓等
	Description string    `json:"description" gorm:"size:500"`
	Effect      string    `json:"effect" gorm:"size:500"`        // 物品效果描述
	MaxStack    int       `json:"max_stack" gorm:"not null;default:999"` // 最大堆叠数量
	CreatedAt   time.Time `json:"created_at"`
	UpdatedAt   time.Time `json:"updated_at"`
}

// 用户物品模型 - 表示用户拥有的物品
type UserItem struct {
	ID        int64     `json:"id" gorm:"primaryKey;autoIncrement"`
	UserID    int64     `json:"user_id" gorm:"not null;index"`
	ItemID    int64     `json:"item_id" gorm:"not null;index"`
	Quantity  int       `json:"quantity" gorm:"not null;default:1"`
	AcquiredAt time.Time `json:"acquired_at"`

	// 关联物品信息
	Item *Item `json:"item" gorm:"foreignKey:ItemID"`
}

// 数据库配置结构体
type DBConfig struct {
	Host          string
	Port          int
	Username      string
	Password      string
	Database      string
	RootUsername  string
	RootPassword  string
}

// 从环境变量或默认值加载配置
func loadConfig() *DBConfig {
	// 尝试从环境变量加载配置，如果没有则使用默认值
	mysqlHost := getEnv("MYSQL_HOST", "mysql")
	mysqlPort := getEnvInt("MYSQL_PORT", 3306)
	mysqlUser := getEnv("MYSQL_USER", "game")
	mysqlPassword := getEnv("MYSQL_PASSWORD", "game")
	mysqlDBName := getEnv("MYSQL_DATABASE", "xianxia_game")
	mysqlRootUser := getEnv("MYSQL_ROOT_USER", "root")
	mysqlRootPassword := getEnv("MYSQL_ROOT_PASSWORD", "root")

	return &DBConfig{
		Host:          mysqlHost,
		Port:          mysqlPort,
		Username:      mysqlUser,
		Password:      mysqlPassword,
		Database:      mysqlDBName,
		RootUsername:  mysqlRootUser,
		RootPassword:  mysqlRootPassword,
	}
}

// 获取环境变量，如果不存在则返回默认值
func getEnv(key, defaultValue string) string {
	value := os.Getenv(key)
	if value == "" {
		return defaultValue
	}
	return value
}

// 获取环境变量的整数值，如果不存在或无法转换则返回默认值
func getEnvInt(key string, defaultValue int) int {
	value := os.Getenv(key)
	if value == "" {
		return defaultValue
	}

	var result int
	fmt.Sscanf(value, "%d", &result)
	return result
}

// 初始化MySQL数据库连接
func initMySQL(dsn string) (*gorm.DB, error) {
	// 创建gorm数据库连接
	mysqlDB, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Info), // 设置日志模式为Info
	})
	if err != nil {
		return nil, fmt.Errorf("MySQL连接失败: %v", err)
	}

	// 获取通用数据库对象
	sqlDB, err := mysqlDB.DB()
	if err != nil {
		return nil, fmt.Errorf("获取SQL DB对象失败: %v", err)
	}

	// 设置连接池参数
	sqlDB.SetMaxOpenConns(100)              // 设置最大打开的连接数
	sqlDB.SetMaxIdleConns(20)               // 设置闲置的连接数
	sqlDB.SetConnMaxLifetime(time.Hour * 4) // 设置连接可复用的最大时间
	sqlDB.SetConnMaxIdleTime(time.Hour * 2) // 设置连接最大空闲时间

	// 验证连接
	if err = sqlDB.Ping(); err != nil {
		return nil, fmt.Errorf("MySQL ping失败: %v", err)
	}

	return mysqlDB, nil
}

// 数据库初始化脚本
// 用于在MySQL容器中创建"xianxia_game"数据库和相关表结构
func main() {
	// 打印环境信息
	log.Printf("开始执行数据库初始化脚本...")

	// 加载配置
	cfg := loadConfig()

	// 1. 首先使用root用户连接到MySQL服务器
	// 构建不包含数据库名的DSN，用于创建数据库
	rootDSN := fmt.Sprintf("%s:%s@tcp(%s:%d)/?charset=utf8mb4&parseTime=True&loc=Local",
		cfg.RootUsername,
		cfg.RootPassword,
		cfg.Host,
		cfg.Port,
	)

	log.Printf("尝试连接MySQL服务器: %s:%d, 用户: %s", cfg.Host, cfg.Port, cfg.RootUsername)

	// 初始化MySQL连接（不指定数据库名）
	rootDB, err := initMySQL(rootDSN)
	if err != nil {
		log.Fatalf("MySQL服务器连接失败: %v", err)
	}

	// 2. 创建数据库
	log.Println("正在创建数据库...")
	dbName := cfg.Database
	if err := rootDB.Exec("CREATE DATABASE IF NOT EXISTS `" + dbName + "` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci").Error;
	err != nil {
		log.Fatalf("创建数据库失败: %v", err)
	}
	log.Printf("数据库 %s 创建成功", dbName)

	// 3. 创建数据库用户（如果不存在）
	log.Println("正在创建数据库用户...")
	createUserSQL := fmt.Sprintf("CREATE USER IF NOT EXISTS '%s'@'%%' IDENTIFIED BY '%s'", 
		cfg.Username, cfg.Password)
	if err := rootDB.Exec(createUserSQL).Error; err != nil {
		log.Fatalf("创建用户失败: %v", err)
	}
	log.Printf("用户 %s 创建成功", cfg.Username)

	// 4. 授予用户权限
	log.Println("正在为用户授予数据库权限...")
	grantSQL := fmt.Sprintf("GRANT ALL PRIVILEGES ON `%s`.* TO '%s'@'%%'", 
		dbName, cfg.Username)
	if err := rootDB.Exec(grantSQL).Error; err != nil {
		log.Fatalf("授予权限失败: %v", err)
	}
	// 刷新权限
	if err := rootDB.Exec("FLUSH PRIVILEGES").Error; err != nil {
		log.Fatalf("刷新权限失败: %v", err)
	}
	log.Printf("已授予用户 %s 对数据库 %s 的所有权限", cfg.Username, dbName)

	// 5. 连接到新创建的数据库并创建表
	log.Println("正在连接到数据库并创建表结构...")
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		cfg.Username,
		cfg.Password,
		cfg.Host,
		cfg.Port,
		dbName,
	)

	xianxiaDB, err := initMySQL(dsn)
	if err != nil {
		log.Fatalf("连接到数据库失败: %v", err)
	}

	// 6. 自动迁移创建表结构
	// User表
	log.Println("正在创建users表...")
	if err := xianxiaDB.AutoMigrate(&User{}); err != nil {
		log.Fatalf("创建users表失败: %v", err)
	}
	log.Println("users表创建成功")

	// Item表 - 物品基础信息表
	log.Println("正在创建items表...")
	if err := xianxiaDB.AutoMigrate(&Item{}); err != nil {
		log.Fatalf("创建items表失败: %v", err)
	}
	log.Println("items表创建成功")

	// UserItem表 - 用户物品表
	log.Println("正在创建user_items表...")
	if err := xianxiaDB.AutoMigrate(&UserItem{}); err != nil {
		log.Fatalf("创建user_items表失败: %v", err)
	}
	log.Println("user_items表创建成功")

	// 7. 插入初始物品数据
	log.Println("正在插入初始物品数据...")
	
	// 根据物品数据表.txt文档插入初始材料、丹药等物品
	items := []Item{
		// 材料类物品 - 可用于合成和修复法宝，炼制丹药，合成符箓
		{Name: "灵草", Type: "材料", Description: "一种蕴含灵气的普通草药，可用于炼制基础丹药", Effect: "炼丹材料"},
		{Name: "灵石", Type: "材料", Description: "蕴含精纯灵气的矿石，是修仙界的通用货币", Effect: "交易货币、提供灵气"},
		{Name: "玄铁", Type: "材料", Description: "坚硬无比的金属，适合打造各种法宝和武器", Effect: "法宝材料"},
		{Name: "朱砂", Type: "材料", Description: "绘制符箓的必备材料，蕴含神秘力量", Effect: "符箓材料"},
		{Name: "灵玉", Type: "材料", Description: "通透的玉石，可用于制作储物袋和传送阵", Effect: "制作储物袋、传送阵"},
		
		// 丹药类物品
		{Name: "培元丹", Type: "丹药", Description: "基础修炼丹药，可增加少量修为", Effect: "使用后获得100点修为"},
		{Name: "回春丹", Type: "丹药", Description: "疗伤圣药，可快速恢复气血", Effect: "使用后恢复50点气血"},
		{Name: "聚气丹", Type: "丹药", Description: "帮助修炼者凝聚灵气，提升修炼效率", Effect: "使用后30分钟内修炼效率提升50%"},
		{Name: "定魂丹", Type: "丹药", Description: "稳定神魂，帮助突破境界", Effect: "使用后突破境界成功率提升10%"},
		
		// 法宝类物品
		{Name: "木剑", Type: "法宝", Description: "普通的木质飞剑，适合初学者使用", Effect: "增加10点攻击力"},
		{Name: "法衣", Type: "法宝", Description: "提供基础防护的法衣", Effect: "增加5点防御力"},
		{Name: "辟邪神雷", Type: "法宝", Description: "由稀有材料天雷竹炼制，金光所致，万邪退散！", Effect: "增加100点攻击力，对一切邪物或邪性法术有奇效"},
		
		// 符箓类物品
		{Name: "火球符", Type: "符箓", Description: "释放一道火球攻击敌人", Effect: "对单个敌人造成30点伤害"},
		{Name: "隐身符", Type: "符箓", Description: "短时间内隐藏自身气息", Effect: "30秒内不会被怪物发现"},
		{Name: "传送符", Type: "符箓", Description: "传送到指定地点", Effect: "立即返回安全区域"},
		// 法术类物品,秘籍
		{Name: "火球术", Type: "法术", Description: "释放一道火球攻击敌人", Effect: "对单个敌人造成30点伤害"},
		{Name: "遁地符", Type: "法术", Description: "短时间内遁入地下", Effect: "遁入地下，可以闪避某些攻击，跨过一些障碍，提高赶路行程"},
		{Name: "飞行术", Type: "法术", Description: "可以在短时间内飞行", Effect: "飞向高空，可以闪避某些攻击，跨过一些障碍，提高赶路行程"},
	}
	
	// 批量插入物品数据
	if err := xianxiaDB.Create(&items).Error; err != nil {
		log.Fatalf("插入物品数据失败: %v", err)
	}
	log.Printf("成功插入%d种物品数据\n", len(items))

	// 8. 为测试用户添加一些初始物品
	log.Println("正在为测试用户添加初始物品...")
	now := time.Now()
	userItems := []UserItem{
		{UserID: 1, ItemID: 1, Quantity: 10, AcquiredAt: now},  // 10株灵草
		{UserID: 1, ItemID: 2, Quantity: 1000, AcquiredAt: now}, // 1000块灵石
		{UserID: 1, ItemID: 6, Quantity: 3, AcquiredAt: now},    // 3颗培元丹
		{UserID: 1, ItemID: 7, Quantity: 2, AcquiredAt: now},    // 2颗回春丹
	}
	
	// 批量插入用户物品数据
	if err := xianxiaDB.Create(&userItems).Error; err != nil {
		log.Fatalf("插入用户物品数据失败: %v", err)
	}
	log.Printf("成功为测试用户添加%d种初始物品\n", len(userItems))

	log.Println("数据库初始化完成！")
}